// import com.alibaba.druid.sql.SQLUtils;
// import com.alibaba.druid.sql.ast.*;
// import com.alibaba.druid.sql.ast.expr.*;
// import com.alibaba.druid.sql.ast.statement.*;
// import com.alibaba.druid.sql.dialect.db2.ast.DB2Object;
// import com.alibaba.druid.sql.dialect.db2.ast.stmt.DB2SelectQueryBlock;
// import com.alibaba.druid.sql.dialect.db2.visitor->DB2ASTVisitorAdapter;
// import com.alibaba.druid.sql.dialect.hive.ast.HiveInsert;
// import com.alibaba.druid.sql.dialect.hive.ast.HiveInsertStatement;
// import com.alibaba.druid.sql.dialect.hive.ast.HiveMultiInsertStatement;
// import com.alibaba.druid.sql.dialect.hive.stmt.HiveCreateTableStatement;
// import com.alibaba.druid.sql.dialect.hive.visitor->HiveASTVisitorAdapter;
// import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey;
// import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorDeclareStatement;
// import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlDeclareStatement;
// import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlRepeatStatement_ptr;
// import com.alibaba.druid.sql.dialect.mysql.ast.statement.*;
// import com.alibaba.druid.sql.dialect.mysql.visitor->MySqlASTVisitorAdapter;
// import com.alibaba.druid.sql.dialect.odps.ast.OdpsCreateTableStatement;
// import com.alibaba.druid.sql.dialect.odps.ast.OdpsSelectQueryBlock;
// import com.alibaba.druid.sql.dialect.odps.visitor->OdpsASTVisitorAdapter;
// import com.alibaba.druid.sql.dialect.oracle.ast.stmt.*;
// import com.alibaba.druid.sql.dialect.oracle.visitor->OracleASTVisitorAdapter;
// import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.*;
// import com.alibaba.druid.sql.dialect.postgresql.visitor->PGASTVisitorAdapter;
// import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerSelectQueryBlock;
// import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerInsertStatement;
// import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerUpdateStatement;
// import com.alibaba.druid.sql.dialect.sqlserver.visitor->SQLServerASTVisitorAdapter;
// import com.alibaba.druid.sql.visitor->SQLASTVisitorAdapter;
// import com.alibaba.druid.util.FnvHash;
// import com.alibaba.druid.util.PGUtils;

#include "SchemaResolveVisitorFactory.h"
#include "../../utils/FnvHash.h"
#include "../../utils/instanceof.h"
#include "../dialect/mysql/ast/MysqlForeignKey.h"
#include "../ast/statement/SQLForeignKeyConstraint.h"
#include "../ast/statement/SQLUpdateSetItem.h"
#include "../ast/statement/SQLLateralViewTableSource.h"
#include "../ast/statement/SQLBlockStatement.h"
#include "../ast/statement/SQLCreateProcedureStatement.h"
#include "../ast/statement/SQLMergeStatement.h"
#include "../ast/statement/SQLCreateFunctionStatement.h"
#include "../ast/statement/SQLUnionQueryTableSource.h"
#include "../ast/statement/SQLAlterTableStatement.h"
#include "../ast/statement/SQLAlterTableItem.h"
#include "../ast/statement/SQLUnionQuery.h"
#include "../ast/statement/SQLSelectQueryBlock.h"
#include "../ast/statement/SQLInsertStatement.h"
#include "../ast/statement/SQLUpdateStatement.h"
#include "../ast/statement/SQLSelectItem.h"
#include "../ast/statement/SQLDeleteStatement.h"
#include "../ast/statement/SQLColumnDefinition.h"
#include "../ast/statement/SQLUniqueConstraint.h"
#include "../ast/statement/SQLWithSubqueryClause.h"
#include "../ast/statement/SQLSubqueryTableSource.h"
#include "../ast/statement/SQLJoinTableSource.h"
#include "../ast/expr/SQLListExpr.h"
#include "../ast/expr/SQLBinaryOpExprGroup.h"
#include "../ast/expr/SQLMethodInvokeExpr.h"
#include "../ast/expr/SQLBinaryOpExpr.h"
#include "../ast/expr/SQLQueryExpr.h"
#include "../ast/expr/SQLAllColumnExpr.h"
#include "../ast/SQLParameter.h"
#include "../ast/SQLDeclareItem.h"
#include "../ast/SQLOver.h"
#include "../ast/SQLName.h"
#include "../dialect/mysql/ast/statement/MySqlCreateTableStatement.h"
#include "../dialect/mysql/ast/statement/MySqlSelectQueryBlock.h"
#include "../dialect/mysql/ast/statement/MySqlUpdateStatement.h"
#include "../dialect/mysql/ast/statement/MySqlInsertStatement.h"
#include "../dialect/sqlserver/ast/SQLServerSelectQueryBlock.h"
#include "../dialect/sqlserver/ast/stmt/SQLServerInsertStatement.h"
#include "SchemaRepository.h"
#include "SchemaObject.h"
#include "../visitor/SQLASTVisitor.h"

SchemaResolveVisitorFactory_MySqlResolveVisitor::SchemaResolveVisitorFactory_MySqlResolveVisitor(SchemaRepository_ptr repository, int options)
{
  // this->schemaResolveVisitorFactory = schemaResolveVisitorFactory;
  this->repository = repository;
  this->options = options;
}

BOOL_ptr SchemaResolveVisitorFactory_MySqlResolveVisitor::visit(MySqlRepeatStatement_ptr x)
{
  return BOOL::TRUE;
}

// BOOL_ptr SchemaResolveVisitorFactory_MySqlResolveVisitor::visit(MySqlDeclareStatement_ptr x)
// {
//   for (SQLDeclareItem_ptr declareItem : x->getVarList())
//   {
//     visit(declareItem);
//   }
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaResolveVisitorFactory_MySqlResolveVisitor::visit(MySqlCursorDeclareStatement x)
// {
//   return BOOL::TRUE;
// }

BOOL_ptr SchemaResolveVisitorFactory_MySqlResolveVisitor::visit(MysqlForeignKey_ptr x)
{
  SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitorFactory_MySqlResolveVisitor), std::dynamic_pointer_cast<SQLForeignKeyConstraint>(x));
  return BOOL::FALSE;
}

BOOL_ptr SchemaResolveVisitorFactory_MySqlResolveVisitor::visit(MySqlSelectQueryBlock_ptr x)
{
  SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitorFactory_MySqlResolveVisitor), std::dynamic_pointer_cast<SQLSelectQueryBlock>(x));
  return BOOL::FALSE;
}

bool SchemaResolveVisitorFactory_MySqlResolveVisitor::visit(SQLSelectItem_ptr x)
{
  SQLExpr_ptr expr = x->getExpr();
  if (instanceof <SQLExpr, SQLIdentifierExpr>(expr))
  {
    SchemaResolveVisitorFactory::resolveIdent(SharedObject(SchemaResolveVisitorFactory_MySqlResolveVisitor), std::dynamic_pointer_cast<SQLIdentifierExpr>(expr));
    return false;
  }

  if (instanceof <SQLExpr, SQLPropertyExpr>(expr))
  {
    SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitorFactory_MySqlResolveVisitor), std::dynamic_pointer_cast<SQLPropertyExpr>(expr));
    return false;
  }

  return true;
}

BOOL_ptr SchemaResolveVisitorFactory_MySqlResolveVisitor::visit(MySqlCreateTableStatement_ptr x)
{
  SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitorFactory_MySqlResolveVisitor), x);
  SQLExprTableSource_ptr like = x->getLike();
  if (like != nullptr)
  {
    like->accept(std::dynamic_pointer_cast<SQLASTVisitor>(SharedObject(SchemaResolveVisitorFactory_MySqlResolveVisitor)));
  }
  return BOOL::FALSE;
}

BOOL_ptr SchemaResolveVisitorFactory_MySqlResolveVisitor::visit(MySqlUpdateStatement_ptr x)
{
  SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitorFactory_MySqlResolveVisitor), std::dynamic_pointer_cast<SQLUpdateStatement>(x));
  return BOOL::FALSE;
}

// BOOL_ptr SchemaResolveVisitorFactory_MySqlResolveVisitor::visit(MySqlDeleteStatement_ptr x)
// {
//   SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitorFactory_MySqlResolveVisitor), x);
//   return BOOL::FALSE;
// }

BOOL_ptr SchemaResolveVisitorFactory_MySqlResolveVisitor::visit(MySqlInsertStatement_ptr x)
{
  SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitorFactory_MySqlResolveVisitor), std::dynamic_pointer_cast<SQLInsertStatement>(x));
  return BOOL::FALSE;
}

// @Override
BOOL_ptr SchemaResolveVisitorFactory_MySqlResolveVisitor::isEnabled(SchemaResolveVisitor_Option_ptr option)
{
  return ((options & option->mask_) != 0)?BOOL::TRUE:BOOL::FALSE;
}

int SchemaResolveVisitorFactory_MySqlResolveVisitor::getOptions()
{
  return options;
}

// @Override
SchemaResolveVisitor_Context_ptr SchemaResolveVisitorFactory_MySqlResolveVisitor::getContext()
{
  return context;
}

SchemaResolveVisitor_Context_ptr SchemaResolveVisitorFactory_MySqlResolveVisitor::createContext(SQLObject_ptr object)
{
  return this->context = SchemaResolveVisitor_Context_ptr(new SchemaResolveVisitor_Context(object, context));
}

// @Override
void SchemaResolveVisitorFactory_MySqlResolveVisitor::popContext()
{
  if (context != nullptr)
  {
    context = context->parent;
  }
}

SchemaRepository_ptr SchemaResolveVisitorFactory_MySqlResolveVisitor::getRepository()
{
  return repository;
}

// class SchemaResolveVisitorFactory_DB2ResolveVisitor : public DB2ASTVisitorAdapter, virtual public SchemaResolveVisitor_ptr
// {
//   public:
//   SchemaRepository_ptr repository;
//   int options;
//   SchemaResolveVisitor_Context_ptr context;

//   DB2ResolveVisitor(SchemaRepository_ptr repository, int options)
//   {
//     this->repository = repository;
//     this->options = options;
//   }

//   BOOL_ptr visit(DB2SelectQueryBlock x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(SQLSelectItem x)
//   {
//     SQLExpr_ptr expr = x->getExpr();
//     if (expr instanceof SQLIdentifierExpr_ptr)
//     {
//       resolveIdent(this, (SQLIdentifierExpr_ptr)expr);
//       return BOOL::FALSE;
//     }

//     if (expr instanceof SQLPropertyExpr)
//     {
//       resolve(this, (SQLPropertyExpr)expr);
//       return BOOL::FALSE;
//     }

//     return BOOL::TRUE;
//   }

//   BOOL_ptr visit(SQLIdentifierExpr_ptr x)
//   {
//     long hash64 = x->hashCode64();
//     if (hash64 == FnvHash::Constants::CURRENT_DATE || hash64 == DB2Object.Constants.CURRENT_TIME)
//     {
//       return BOOL::FALSE;
//     }

//     resolveIdent(this, x);
//     return BOOL::TRUE;
//   }

//   // @Override
//   BOOL_ptr isEnabled(SchemaResolveVisitor_Option_ptr option)
//   {
//     return (options & option.mask) != 0;
//   }

//   int getOptions()
//   {
//     return options;
//   }

//   // @Override
//   SchemaResolveVisitor_Context_ptr getContext()
//   {
//     return context;
//   }

//   SchemaResolveVisitor_Context_ptr createContext(SQLObject object)
//   {
//     return this->context = new SchemaResolveVisitor_Context_ptr(object, context);
//   }

//   // @Override
//   void popContext()
//   {
//     if (context != nullptr)
//     {
//       context = context.parent;
//     }
//   }

//   // @Override
//   SchemaRepository_ptr getRepository()
//   {
//     return repository;
//   }
// };

SchemaResolveVisitorFactory_OracleResolveVisitor::SchemaResolveVisitorFactory_OracleResolveVisitor(SchemaRepository_ptr repository, int options)
{
  // this->schemaResolveVisitorFactory = schemaResolveVisitorFactory;
  this->repository = repository;
  this->options = options;
}

// BOOL_ptr SchemaResolveVisitorFactory_OracleResolveVisitor::visit(OracleCreatePackageStatement_ptr x)
// {
//   SchemaResolveVisitor_Context_ptr ctx = createContext(x);

//   for (SQLStatement stmt : x->getStatements())
//   {
//     stmt->accept(this);
//   }

//   popContext();
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaResolveVisitorFactory_OracleResolveVisitor::visit(OracleForStatement_ptr x)
// {
//   SchemaResolveVisitor_Context_ptr ctx = createContext(x);

//   SQLName index = x->getIndex();
//   SQLExpr_ptr range = x->getRange();

//   if (index != nullptr)
//   {
//     SQLDeclareItem_ptr declareItem = new SQLDeclareItem_ptr(index, nullptr);
//     declareItem.setParent(x);

//     if (index instanceof SQLIdentifierExpr_ptr)
//     {
//       ((SQLIdentifierExpr_ptr)index).setResolvedDeclareItem(declareItem);
//     }
//     declareItem.setResolvedObject(range);
//     ctx->declare(declareItem);
//     if (range instanceof SQLQueryExpr)
//     {
//       SQLSelect select = ((SQLQueryExpr)range).getSubQuery();
//       SQLSubqueryTableSource tableSource = new SQLSubqueryTableSource(select);
//       declareItem.setResolvedObject(tableSource);
//     }

//     index->accept(this);
//   }

//   if (range != nullptr)
//   {
//     range->accept(this);
//   }

//   for (SQLStatement stmt : x->getStatements())
//   {
//     stmt->accept(this);
//   }

//   popContext();
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaResolveVisitorFactory_OracleResolveVisitor::visit(OracleForeignKey_ptr x)
// {
//   resolve(this, x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaResolveVisitorFactory_OracleResolveVisitor::visit(OracleSelectTableReference_ptr x)
// {
//   resolve(this, x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaResolveVisitorFactory_OracleResolveVisitor::visit(OracleSelectQueryBlock_ptr x)
// {
//   resolve(this, x);
//   return BOOL::FALSE;
// }

bool SchemaResolveVisitorFactory_OracleResolveVisitor::visit(SQLSelectItem_ptr x)
{
  SQLExpr_ptr expr = x->getExpr();
  if (instanceof <SQLExpr, SQLIdentifierExpr>(expr))
  {
    SchemaResolveVisitorFactory::resolveIdent(SharedObject(SchemaResolveVisitorFactory_OracleResolveVisitor), std::dynamic_pointer_cast<SQLIdentifierExpr>(expr));
    return false;
  }

  if (instanceof <SQLExpr, SQLPropertyExpr>(expr))
  {
    SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitorFactory_OracleResolveVisitor), std::dynamic_pointer_cast<SQLPropertyExpr>(expr));
    return false;
  }

  return true;
}

bool SchemaResolveVisitorFactory_OracleResolveVisitor::visit(SQLIdentifierExpr_ptr x)
{
  if (x->nameHashCode64() == FnvHash::Constants::ROWNUM)
  {
    return false;
  }

  SchemaResolveVisitorFactory::resolveIdent(SharedObject(SchemaResolveVisitorFactory_OracleResolveVisitor), x);
  return true;
}

// BOOL_ptr SchemaResolveVisitorFactory_OracleResolveVisitor::visit(OracleCreateTableStatement_ptr x)
// {
//   SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitorFactory_OracleResolveVisitor), x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaResolveVisitorFactory_OracleResolveVisitor::visit(OracleUpdateStatement_ptr x)
// {
//   SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitorFactory_OracleResolveVisitor), x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaResolveVisitorFactory_OracleResolveVisitor::visit(OracleDeleteStatement_ptr x)
// {
//   SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitorFactory_OracleResolveVisitor), x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaResolveVisitorFactory_OracleResolveVisitor::visit(OracleMultiInsertStatement_ptr x)
// {
//   SchemaResolveVisitor_Context_ptr ctx = createContext(x);

//   SQLSelect select = x->getSubQuery();
//   SchemaResolveVisitorFactory::visit(select);

//   OracleSelectSubqueryTableSource tableSource = new OracleSelectSubqueryTableSource(select);
//   tableSource.setParent(x);
//   ctx->setTableSource(tableSource);

//   for (OracleMultiInsertStatement.Entry entry : x->getEntries())
//   {
//     entry->accept(this);
//   }

//   popContext();
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaResolveVisitorFactory_OracleResolveVisitor::visit(OracleMultiInsertStatement.InsertIntoClause x)
// {
//   for (SQLExpr_ptr column : x->getColumns())
//   {
//     if (column instanceof SQLIdentifierExpr_ptr)
//     {
//       SQLIdentifierExpr_ptr identColumn = (SQLIdentifierExpr_ptr)column;
//       identColumn.setResolvedTableSource(x->getTableSource());
//     }
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr SchemaResolveVisitorFactory_OracleResolveVisitor::visit(OracleInsertStatement x)
// {
//   SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitorFactory_OracleResolveVisitor), x);
//   return BOOL::FALSE;
// }

// @Override
BOOL_ptr SchemaResolveVisitorFactory_OracleResolveVisitor::isEnabled(SchemaResolveVisitor_Option_ptr option)
{
  return ((options & option->mask_) != 0)?BOOL::TRUE:BOOL::FALSE;
}

int SchemaResolveVisitorFactory_OracleResolveVisitor::getOptions()
{
  return options;
}

// @Override
SchemaResolveVisitor_Context_ptr SchemaResolveVisitorFactory_OracleResolveVisitor::getContext()
{
  return context;
}

SchemaResolveVisitor_Context_ptr SchemaResolveVisitorFactory_OracleResolveVisitor::createContext(SQLObject_ptr object)
{
  return this->context = SchemaResolveVisitor_Context_ptr(new SchemaResolveVisitor_Context(object, context));
}

// @Override
void SchemaResolveVisitorFactory_OracleResolveVisitor::popContext()
{
  if (context != nullptr)
  {
    context = context->parent;
  }
}

SchemaRepository_ptr SchemaResolveVisitorFactory_OracleResolveVisitor::getRepository()
{
  return repository;
}

// class SchemaResolveVisitorFactory_OdpsResolveVisitor : public OdpsASTVisitorAdapter, virtual public SchemaResolveVisitor_ptr
// {
//   public:
//   int options;
//   SchemaRepository_ptr repository;
//   SchemaResolveVisitor_Context_ptr context;

//   OdpsResolveVisitor(SchemaRepository_ptr repository, int options)
//   {
//     this->repository = repository;
//     this->options = options;
//   }

//   BOOL_ptr visit(OdpsSelectQueryBlock x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(SQLSelectItem x)
//   {
//     SQLExpr_ptr expr = x->getExpr();
//     if (expr instanceof SQLIdentifierExpr_ptr)
//     {
//       resolveIdent(this, (SQLIdentifierExpr_ptr)expr);
//       return BOOL::FALSE;
//     }

//     if (expr instanceof SQLPropertyExpr)
//     {
//       resolve(this, (SQLPropertyExpr)expr);
//       return BOOL::FALSE;
//     }

//     return BOOL::TRUE;
//   }

//   BOOL_ptr visit(OdpsCreateTableStatement x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(HiveInsert x)
//   {
//     SchemaResolveVisitor_Context_ptr ctx = createContext(x);

//     SQLExprTableSource_ptr tableSource = x->getTableSource();
//     if (tableSource != nullptr)
//     {
//       ctx->setTableSource(x->getTableSource());
//       visit(tableSource);
//     }

//     List<SQLAssignItem> partitions = x->getPartitions();
//     if (partitions != nullptr)
//     {
//       for (SQLAssignItem item : partitions)
//       {
//         item->accept(this);
//       }
//     }

//     SQLSelect select = x->getQuery();
//     if (select != nullptr)
//     {
//       visit(select);
//     }

//     popContext();
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(HiveInsertStatement x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   // @Override
//   BOOL_ptr isEnabled(SchemaResolveVisitor_Option_ptr option)
//   {
//     return (options & option.mask) != 0;
//   }

//   int getOptions()
//   {
//     return options;
//   }

//   // @Override
//   SchemaResolveVisitor_Context_ptr getContext()
//   {
//     return context;
//   }

//   SchemaResolveVisitor_Context_ptr createContext(SQLObject object)
//   {
//     return this->context = new SchemaResolveVisitor_Context_ptr(object, context);
//   }

//   // @Override
//   void popContext()
//   {
//     if (context != nullptr)
//     {
//       context = context.parent;
//     }
//   }

//   SchemaRepository_ptr getRepository()
//   {
//     return repository;
//   }
// };

// class SchemaResolveVisitorFactory_HiveResolveVisitor : public HiveASTVisitorAdapter, virtual public SchemaResolveVisitor_ptr
// {
//   public:
//   int options;
//   SchemaRepository_ptr repository;
//   SchemaResolveVisitor_Context_ptr context;

//   HiveResolveVisitor(SchemaRepository_ptr repository, int options)
//   {
//     this->repository = repository;
//     this->options = options;
//   }

//   BOOL_ptr visit(OdpsSelectQueryBlock x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(SQLSelectItem x)
//   {
//     SQLExpr_ptr expr = x->getExpr();
//     if (expr instanceof SQLIdentifierExpr_ptr)
//     {
//       resolveIdent(this, (SQLIdentifierExpr_ptr)expr);
//       return BOOL::FALSE;
//     }

//     if (expr instanceof SQLPropertyExpr)
//     {
//       resolve(this, (SQLPropertyExpr)expr);
//       return BOOL::FALSE;
//     }

//     return BOOL::TRUE;
//   }

//   BOOL_ptr visit(HiveCreateTableStatement x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(HiveInsert x)
//   {
//     SchemaResolveVisitor_Context_ptr ctx = createContext(x);

//     SQLExprTableSource_ptr tableSource = x->getTableSource();
//     if (tableSource != nullptr)
//     {
//       ctx->setTableSource(x->getTableSource());
//       visit(tableSource);
//     }

//     List<SQLAssignItem> partitions = x->getPartitions();
//     if (partitions != nullptr)
//     {
//       for (SQLAssignItem item : partitions)
//       {
//         item->accept(this);
//       }
//     }

//     SQLSelect select = x->getQuery();
//     if (select != nullptr)
//     {
//       visit(select);
//     }

//     popContext();
//     return BOOL::FALSE;
//   }

//   // @Override
//   BOOL_ptr isEnabled(SchemaResolveVisitor_Option_ptr option)
//   {
//     return (options & option.mask) != 0;
//   }

//   int getOptions()
//   {
//     return options;
//   }

//   // @Override
//   SchemaResolveVisitor_Context_ptr getContext()
//   {
//     return context;
//   }

//   SchemaResolveVisitor_Context_ptr createContext(SQLObject object)
//   {
//     return this->context = new SchemaResolveVisitor_Context_ptr(object, context);
//   }

//   // @Override
//   void popContext()
//   {
//     if (context != nullptr)
//     {
//       context = context.parent;
//     }
//   }

//   SchemaRepository_ptr getRepository()
//   {
//     return repository;
//   }
// };

// class SchemaResolveVisitorFactory_PGResolveVisitor : public PGASTVisitorAdapter, virtual public SchemaResolveVisitor_ptr
// {
//   public:
//   int options;
//   SchemaRepository_ptr repository;
//   SchemaResolveVisitor_Context_ptr context;

//   PGResolveVisitor(SchemaRepository_ptr repository, int options)
//   {
//     this->repository = repository;
//     this->options = options;
//   }

//   BOOL_ptr visit(PGSelectQueryBlock x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(PGFunctionTableSource x)
//   {
//     for (SQLParameter_ptr parameter : x->getParameters())
//     {
//       SQLName name = parameter.getName();
//       if (name instanceof SQLIdentifierExpr_ptr)
//       {
//         SQLIdentifierExpr_ptr identName = (SQLIdentifierExpr_ptr)name;
//         identName.setResolvedTableSource(x);
//       }
//     }

//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(SQLSelectItem x)
//   {
//     SQLExpr_ptr expr = x->getExpr();
//     if (expr instanceof SQLIdentifierExpr_ptr)
//     {
//       resolveIdent(this, (SQLIdentifierExpr_ptr)expr);
//       return BOOL::FALSE;
//     }

//     if (expr instanceof SQLPropertyExpr)
//     {
//       resolve(this, (SQLPropertyExpr)expr);
//       return BOOL::FALSE;
//     }

//     return BOOL::TRUE;
//   }

//   BOOL_ptr visit(SQLIdentifierExpr_ptr x)
//   {
//     if (PGUtils.isPseudoColumn(x->nameHashCode64()))
//     {
//       return BOOL::FALSE;
//     }

//     resolveIdent(this, x);
//     return BOOL::TRUE;
//   }

//   BOOL_ptr visit(PGUpdateStatement x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(PGDeleteStatement x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(PGSelectStatement x)
//   {
//     createContext(x);
//     visit(x->getSelect());
//     popContext();
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(PGInsertStatement x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   // @Override
//   BOOL_ptr isEnabled(SchemaResolveVisitor_Option_ptr option)
//   {
//     return (options & option.mask) != 0;
//   }

//   int getOptions()
//   {
//     return options;
//   }

//   // @Override
//   SchemaResolveVisitor_Context_ptr getContext()
//   {
//     return context;
//   }

//   SchemaResolveVisitor_Context_ptr createContext(SQLObject object)
//   {
//     return this->context = new SchemaResolveVisitor_Context_ptr(object, context);
//   }

//   // @Override
//   void popContext()
//   {
//     if (context != nullptr)
//     {
//       context = context.parent;
//     }
//   }

//   SchemaRepository_ptr getRepository()
//   {
//     return repository;
//   }
// };

SchemaResolveVisitorFactory_SQLServerResolveVisitor::SchemaResolveVisitorFactory_SQLServerResolveVisitor(SchemaRepository_ptr repository, int options)
{
  // this->schemaResolveVisitorFactory = schemaResolveVisitorFactory;
  this->repository = repository;
  this->options = options;
}

BOOL_ptr SchemaResolveVisitorFactory_SQLServerResolveVisitor::visit(SQLServerSelectQueryBlock_ptr x)
{
  SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitorFactory_SQLServerResolveVisitor), std::dynamic_pointer_cast<SQLSelectQueryBlock>(x));
  return BOOL::FALSE;
}

bool SchemaResolveVisitorFactory_SQLServerResolveVisitor::visit(SQLSelectItem_ptr x)
{
  SQLExpr_ptr expr = x->getExpr();
  if (instanceof <SQLExpr, SQLIdentifierExpr>(expr))
  {
    SchemaResolveVisitorFactory::resolveIdent(SharedObject(SchemaResolveVisitorFactory_SQLServerResolveVisitor), std::dynamic_pointer_cast<SQLIdentifierExpr>(expr));
    return false;
  }

  if (instanceof <SQLExpr, SQLPropertyExpr>(expr))
  {
    SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitorFactory_SQLServerResolveVisitor), std::dynamic_pointer_cast<SQLPropertyExpr>(expr));
    return false;
  }

  return true;
}

// BOOL_ptr SchemaResolveVisitorFactory_SQLServerResolveVisitor::visit(SQLServerUpdateStatement_ptr x)
// {
//   SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitorFactory_SQLServerResolveVisitor), x);
//   return BOOL::FALSE;
// }

BOOL_ptr SchemaResolveVisitorFactory_SQLServerResolveVisitor::visit(SQLServerInsertStatement_ptr x)
{
  SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitorFactory_SQLServerResolveVisitor), std::dynamic_pointer_cast<SQLInsertStatement>(x));
  return BOOL::FALSE;
}

// @Override
BOOL_ptr SchemaResolveVisitorFactory_SQLServerResolveVisitor::isEnabled(SchemaResolveVisitor_Option_ptr option)
{
  return ((options & option->mask_) != 0)?BOOL::TRUE:BOOL::FALSE;
}

int SchemaResolveVisitorFactory_SQLServerResolveVisitor::getOptions()
{
  return options;
}

// @Override
SchemaResolveVisitor_Context_ptr SchemaResolveVisitorFactory_SQLServerResolveVisitor::getContext()
{
  return context;
}

SchemaResolveVisitor_Context_ptr SchemaResolveVisitorFactory_SQLServerResolveVisitor::createContext(SQLObject_ptr object)
{
  return this->context = SchemaResolveVisitor_Context_ptr(new SchemaResolveVisitor_Context(object, context));
}

// @Override
void SchemaResolveVisitorFactory_SQLServerResolveVisitor::popContext()
{
  if (context != nullptr)
  {
    context = context->parent;
  }
}

SchemaRepository_ptr SchemaResolveVisitorFactory_SQLServerResolveVisitor::getRepository()
{
  return repository;
}

SchemaResolveVisitorFactory_SQLResolveVisitor::SchemaResolveVisitorFactory_SQLResolveVisitor(SchemaRepository_ptr repository, int options)
{
  // this->schemaResolveVisitorFactory = schemaResolveVisitorFactory;
  this->repository = repository;
  this->options = options;
}

bool SchemaResolveVisitorFactory_SQLResolveVisitor::visit(SQLSelectItem_ptr x)
{
  SQLExpr_ptr expr = x->getExpr();
  if (instanceof <SQLExpr, SQLIdentifierExpr>(expr))
  {
    SchemaResolveVisitorFactory::resolveIdent(SharedObject(SchemaResolveVisitorFactory_SQLResolveVisitor), std::dynamic_pointer_cast<SQLIdentifierExpr>(expr));
    return false;
  }

  if (instanceof <SQLExpr, SQLPropertyExpr>(expr))
  {
    SchemaResolveVisitorFactory::resolve(SharedObject(SchemaResolveVisitorFactory_SQLResolveVisitor), std::dynamic_pointer_cast<SQLPropertyExpr>(expr));
    return false;
  }

  return true;
}

// @Override
BOOL_ptr SchemaResolveVisitorFactory_SQLResolveVisitor::isEnabled(SchemaResolveVisitor_Option_ptr option)
{
  return ((options & option->mask_) != 0)?BOOL::TRUE:BOOL::FALSE;
}

int SchemaResolveVisitorFactory_SQLResolveVisitor::getOptions()
{
  return options;
}

// @Override
SchemaResolveVisitor_Context_ptr SchemaResolveVisitorFactory_SQLResolveVisitor::getContext()
{
  return context;
}

SchemaResolveVisitor_Context_ptr SchemaResolveVisitorFactory_SQLResolveVisitor::createContext(SQLObject_ptr object)
{
  return this->context = SchemaResolveVisitor_Context_ptr(new SchemaResolveVisitor_Context(object, context));
}

// @Override
void SchemaResolveVisitorFactory_SQLResolveVisitor::popContext()
{
  if (context != nullptr)
  {
    context = context->parent;
  }
}

SchemaRepository_ptr SchemaResolveVisitorFactory_SQLResolveVisitor::getRepository()
{
  return repository;
}

void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLCreateTableStatement_ptr x)
{
  SchemaResolveVisitor_Context_ptr ctx = visitor->createContext(x);

  SQLExprTableSource_ptr table = x->getTableSource();
  ctx->setTableSource(table);

  table->accept(visitor);

  SQLTableElement_list_ptr elements = x->getTableElementList();
  auto it_elements = elements->begin();
  for (int i = 0; i < elements->size(); i++)
  {
    std::advance(it_elements, i);
    SQLTableElement_ptr e = *it_elements;
    if (instanceof <SQLTableElement, SQLColumnDefinition>(e))
    {
      SQLColumnDefinition_ptr columnn = std::dynamic_pointer_cast<SQLColumnDefinition>(e);
      SQLName_ptr columnnName = columnn->getName();
      if (instanceof <SQLName, SQLIdentifierExpr>(columnnName))
      {
        SQLIdentifierExpr_ptr identifierExpr = std::dynamic_pointer_cast<SQLIdentifierExpr>(columnnName);
        identifierExpr->setResolvedTableSource(table);
        identifierExpr->setResolvedColumn(columnn);
      }
    }
    else if (instanceof <SQLTableElement, SQLUniqueConstraint>(e))
    {
      SQLSelectOrderByItem_list_ptr columns = (std::dynamic_pointer_cast<SQLUniqueConstraint>(e))->getColumns();
      for (SQLSelectOrderByItem_ptr orderByItem : *columns)
      {
        SQLExpr_ptr orderByItemExpr = orderByItem->getExpr();
        if (instanceof <SQLExpr, SQLIdentifierExpr>(orderByItemExpr))
        {
          SQLIdentifierExpr_ptr identifierExpr = std::dynamic_pointer_cast<SQLIdentifierExpr>(orderByItemExpr);
          identifierExpr->setResolvedTableSource(table);

          SQLColumnDefinition_ptr column = x->findColumn(identifierExpr->nameHashCode64());
          if (column != nullptr)
          {
            identifierExpr->setResolvedColumn(column);
          }
        }
      }
    }
    else
    {
      e->accept(visitor);
    }
  }

  SQLSelect_ptr select = x->getSelect();
  if (select != nullptr)
  {
    visitor->visit(select);
  }

  SchemaRepository_ptr repository = visitor->getRepository();
  if (repository != nullptr)
  {
    repository->acceptCreateTable(x);
  }

  visitor->popContext();

  SQLExprTableSource_ptr like = x->getLike();
  if (like != nullptr)
  {
    like->accept(visitor);
  }
}

void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLUpdateStatement_ptr x)
{
  SchemaResolveVisitor_Context_ptr ctx = visitor->createContext(x);

  SQLWithSubqueryClause_ptr with = x->getWith();
  if (with != nullptr)
  {
    with->accept(visitor);
  }

  SQLTableSource_ptr table = x->getTableSource();
  SQLTableSource_ptr from = x->getFrom();

  ctx->setTableSource(table);
  ctx->setFrom(from);

  table->accept(visitor);
  if (from != nullptr)
  {
    from->accept(visitor);
  }

  SQLUpdateSetItem_list_ptr items = x->getItems();
  for (SQLUpdateSetItem_ptr item : *items)
  {
    SQLExpr_ptr column = item->getColumn();
    if (instanceof <SQLExpr, SQLIdentifierExpr>(column))
    {
      SQLIdentifierExpr_ptr identifierExpr = std::dynamic_pointer_cast<SQLIdentifierExpr>(column);
      identifierExpr->setResolvedTableSource(table);
      visitor->visit(identifierExpr);
    }
    else if (instanceof <SQLExpr, SQLListExpr>(column))
    {
      SQLListExpr_ptr columnGroup = std::dynamic_pointer_cast<SQLListExpr>(column);
      for (SQLExpr_ptr columnGroupItem : *columnGroup->getItems())
      {
        if (instanceof <SQLExpr, SQLIdentifierExpr>(columnGroupItem))
        {
          SQLIdentifierExpr_ptr identifierExpr = std::dynamic_pointer_cast<SQLIdentifierExpr>(columnGroupItem);
          identifierExpr->setResolvedTableSource(table);
          visitor->visit(identifierExpr);
        }
        else
        {
          columnGroupItem->accept(visitor);
        }
      }
    }
    else
    {
      column->accept(visitor);
    }
    SQLExpr_ptr value = item->getValue();
    if (value != nullptr)
    {
      value->accept(visitor);
    }
  }

  SQLExpr_ptr where = x->getWhere();
  if (where != nullptr)
  {
    where->accept(visitor);
  }

  SQLOrderBy_ptr orderBy = x->getOrderBy();
  if (orderBy != nullptr)
  {
    orderBy->accept(visitor);
  }

  for (SQLExpr_ptr sqlExpr : *x->getReturning())
  {
    sqlExpr->accept(visitor);
  }

  visitor->popContext();
}

void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLDeleteStatement_ptr x)
{
  SchemaResolveVisitor_Context_ptr ctx = visitor->createContext(x);

  SQLWithSubqueryClause_ptr with = x->getWith();
  if (with != nullptr)
  {
    visitor->visit(with);
  }

  SQLTableSource_ptr table = x->getTableSource();
  SQLTableSource_ptr from = x->getFrom();

  if (from == nullptr)
  {
    from = x->getUsing();
  }

  if (table == nullptr && from != nullptr)
  {
    table = from;
    from = nullptr;
  }

  if (from != nullptr)
  {
    ctx->setFrom(from);
    from->accept(visitor);
  }

  if (table != nullptr)
  {
    if (from != nullptr && instanceof <SQLTableSource, SQLExprTableSource>(table))
    {
      SQLExpr_ptr tableExpr = (std::dynamic_pointer_cast<SQLExprTableSource>(table))->getExpr();
      if (instanceof <SQLExpr, SQLPropertyExpr>(tableExpr) &&
                         (std::dynamic_pointer_cast<SQLPropertyExpr>(tableExpr))->getName()->c_str() == "*")
      {
        string_ptr alias = (std::dynamic_pointer_cast<SQLPropertyExpr>(tableExpr))->getOwnernName();
        SQLTableSource_ptr refTableSource = from->findTableSource(alias);
        if (refTableSource != nullptr)
        {
          (std::dynamic_pointer_cast<SQLPropertyExpr>(tableExpr))->setResolvedTableSource(refTableSource);
        }
      }
    }
    table->accept(visitor);
    ctx->setTableSource(table);
  }

  SQLExpr_ptr where = x->getWhere();
  if (where != nullptr)
  {
    where->accept(visitor);
  }

  visitor->popContext();
}

void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLInsertStatement_ptr x)
{
  SchemaResolveVisitor_Context_ptr ctx = visitor->createContext(x);

  SQLWithSubqueryClause_ptr with = x->getWith();
  if (with != nullptr)
  {
    visitor->visit(with);
  }

  SQLTableSource_ptr table = x->getTableSource();

  ctx->setTableSource(table);

  if (table != nullptr)
  {
    table->accept(visitor);
  }

  for (SQLExpr_ptr column : *x->getColumns())
  {
    column->accept(visitor);
  }

  // if (instanceof<SQLInsertStatement, HiveInsertStatement>(x)  )
  // {
  //   for (SQLAssignItem item : ((HiveInsertStatement)x).getPartitions())
  //   {
  //     item->accept(visitor);
  //   }
  // }

  for (SQLInsertStatement_ValuesClause_ptr valuesClause : *x->getValuesList())
  {
    valuesClause->accept(visitor);
  }

  SQLSelect_ptr query = x->getQuery();
  if (query != nullptr)
  {
    visitor->visit(query);
  }

  visitor->popContext();
}

void SchemaResolveVisitorFactory::resolveIdent(SchemaResolveVisitor_ptr visitor, SQLIdentifierExpr_ptr x)
{
  SchemaResolveVisitor_Context_ptr ctx = visitor->getContext();
  if (ctx == nullptr)
  {
    return;
  }

  string_ptr ident = x->getName();
  long hash = x->nameHashCode64();
  SQLTableSource_ptr tableSource = nullptr;

  if ((hash == FnvHash::Constants::LEVEL ||
       hash == FnvHash::Constants::CONNECT_BY_ISCYCLE) &&
      instanceof <SQLObject, SQLSelectQueryBlock>(ctx->object))
  {
    SQLSelectQueryBlock_ptr queryBlock = std::dynamic_pointer_cast<SQLSelectQueryBlock>(ctx->object);
    if (queryBlock->getStartWith() != nullptr ||
        queryBlock->getConnectBy() != nullptr)
    {
      return;
    }
  }

  SQLTableSource_ptr ctxTable = ctx->getTableSource();

  if (instanceof <SQLTableSource, SQLJoinTableSource>(ctxTable))
  {
    SQLJoinTableSource_ptr join = std::dynamic_pointer_cast<SQLJoinTableSource>(ctxTable);
    tableSource = join->findTableSourceWithColumn(hash, ident, visitor->getOptions());
    if (tableSource == nullptr)
    {
      SQLTableSource_ptr left = join->getLeft(), right = join->getRight();

      if (instanceof <SQLTableSource, SQLSubqueryTableSource>(left) &&
          instanceof <SQLTableSource, SQLExprTableSource>(right))
      {
        SQLSelect_ptr leftSelect = (std::dynamic_pointer_cast<SQLSubqueryTableSource>(left))->getSelect();
        if (instanceof <SQLSelectQuery, SQLSelectQueryBlock>(leftSelect->getQuery()))
        {
          BOOL_ptr hasAllColumn = (std::dynamic_pointer_cast<SQLSelectQueryBlock>(leftSelect->getQuery()))->selectItemHasAllColumn();
          if (!hasAllColumn)
          {
            tableSource = right;
          }
        }
      }
      else if (instanceof <SQLTableSource, SQLSubqueryTableSource>(right) &&
               instanceof <SQLTableSource, SQLExprTableSource>(left))
      {
        SQLSelect_ptr rightSelect = (std::dynamic_pointer_cast<SQLSubqueryTableSource>(right))->getSelect();
        if (instanceof <SQLSelectQuery, SQLSelectQueryBlock>(rightSelect->getQuery()))
        {
          BOOL_ptr hasAllColumn = (std::dynamic_pointer_cast<SQLSelectQueryBlock>(rightSelect->getQuery()))->selectItemHasAllColumn();
          if (!hasAllColumn)
          {
            tableSource = left;
          }
        }
      }
      else if (instanceof <SQLTableSource, SQLExprTableSource>(left) && instanceof <SQLTableSource, SQLExprTableSource>(right))
      {
        SQLExprTableSource_ptr leftExprTableSource = std::dynamic_pointer_cast<SQLExprTableSource>(left);
        SQLExprTableSource_ptr rightExprTableSource = std::dynamic_pointer_cast<SQLExprTableSource>(right);

        if (leftExprTableSource->getSchemaObject() != nullptr && rightExprTableSource->getSchemaObject() == nullptr)
        {
          tableSource = rightExprTableSource;
        }
        else if (rightExprTableSource->getSchemaObject() != nullptr && leftExprTableSource->getSchemaObject() == nullptr)
        {
          tableSource = leftExprTableSource;
        }
      }
    }
  }
  else if (instanceof <SQLTableSource, SQLSubqueryTableSource>(ctxTable))
  {
    tableSource = ctxTable->findTableSourceWithColumn(hash, ident, visitor->getOptions());
  }
  else if (instanceof <SQLTableSource, SQLLateralViewTableSource>(ctxTable))
  {
    tableSource = ctxTable->findTableSourceWithColumn(hash, ident, visitor->getOptions());

    if (tableSource == nullptr)
    {
      tableSource = (std::dynamic_pointer_cast<SQLLateralViewTableSource>(ctxTable))->getTableSource();
    }
  }
  else
  {
    for (SchemaResolveVisitor_Context_ptr parentCtx = ctx;
         parentCtx != nullptr;
         parentCtx = parentCtx->parent)
    {
      SQLDeclareItem_ptr declareItem = parentCtx->findDeclare(hash);
      if (declareItem != nullptr)
      {
        x->setResolvedDeclareItem(declareItem);
        return;
      }

      if (instanceof <SQLObject, SQLBlockStatement>(parentCtx->object))
      {
        SQLBlockStatement_ptr block = std::dynamic_pointer_cast<SQLBlockStatement>(parentCtx->object);
        SQLParameter_ptr parameter = block->findParameter(hash);
        if (parameter != nullptr)
        {
          x->setResolvedParameter(parameter);
          return;
        }
      }
      else if (instanceof <SQLObject, SQLCreateProcedureStatement>(parentCtx->object))
      {
        SQLCreateProcedureStatement_ptr createProc = std::dynamic_pointer_cast<SQLCreateProcedureStatement>(parentCtx->object);
        SQLParameter_ptr parameter = createProc->findParameter(hash);
        if (parameter != nullptr)
        {
          x->setResolvedParameter(parameter);
          return;
        }
      }
    }

    tableSource = ctxTable;
    if (instanceof <SQLTableSource, SQLExprTableSource>(tableSource))
    {
      SchemaObject_ptr table = (std::dynamic_pointer_cast<SQLExprTableSource>(tableSource))->getSchemaObject();
      if (table != nullptr)
      {
        if (table->findColumn(hash) == nullptr)
        {
          SQLCreateTableStatement_ptr createStmt = nullptr;
          {
            SQLStatement_ptr smt = table->getStatement();
            if (instanceof <SQLStatement, SQLCreateTableStatement>(smt))
            {
              createStmt = std::dynamic_pointer_cast<SQLCreateTableStatement>(smt);
            }
          }

          if (createStmt != nullptr && createStmt->getTableElementList()->size() > 0)
          {
            tableSource = nullptr; // maybe parent
          }
        }
      }
    }
  }

  if (instanceof <SQLTableSource, SQLExprTableSource>(tableSource))
  {
    SQLExpr_ptr expr = (std::dynamic_pointer_cast<SQLExprTableSource>(tableSource))->getExpr();

    if (instanceof <SQLExpr, SQLMethodInvokeExpr>(expr))
    {
      SQLMethodInvokeExpr_ptr func = std::dynamic_pointer_cast<SQLMethodInvokeExpr>(expr);
      if (func->methodNameHashCode64() == FnvHash::Constants::ANN)
      {
        auto it_getArguments = func->getArguments()->begin();
        std::advance(it_getArguments, 0);
        expr = *it_getArguments;
      }
    }

    if (instanceof <SQLExpr, SQLIdentifierExpr>(expr))
    {
      SQLIdentifierExpr_ptr identExpr = std::dynamic_pointer_cast<SQLIdentifierExpr>(expr);
      long identHash = identExpr->nameHashCode64();

      tableSource = unwrapAlias(ctx, tableSource, identHash);
    }
  }

  if (tableSource != nullptr)
  {
    x->setResolvedTableSource(tableSource);

    SQLColumnDefinition_ptr column = tableSource->findColumn(hash);
    if (column != nullptr)
    {
      x->setResolvedColumn(column);
    }

    if (instanceof <SQLTableSource, SQLJoinTableSource>(ctxTable))
    {
      string_ptr alias = tableSource->computeAlias();
      if (alias == nullptr || instanceof <SQLTableSource, SQLWithSubqueryClause_Entry>(tableSource))
      {
        return;
      }

      if (visitor->isEnabled(SchemaResolveVisitor_Option::ResolveIdentifierAlias))
      {
        SQLPropertyExpr_ptr propertyExpr = SQLPropertyExpr_ptr(new SQLPropertyExpr(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(alias)), ident, hash));
        propertyExpr->setResolvedColumn(std::dynamic_pointer_cast<SQLColumnDefinition>(x->getResolvedColumn()));
        propertyExpr->setResolvedTableSource(x->getResolvedTableSource());
        SQLUtils::replaceInParent(x, propertyExpr);
      }
    }
  }

  if (x->getResolvedColumn() == nullptr && x->getResolvedTableSource() == nullptr)
  {
    for (SchemaResolveVisitor_Context_ptr parentCtx = ctx;
         parentCtx != nullptr;
         parentCtx = parentCtx->parent)
    {
      SQLDeclareItem_ptr declareItem = parentCtx->findDeclare(hash);
      if (declareItem != nullptr)
      {
        x->setResolvedDeclareItem(declareItem);
        return;
      }

      if (instanceof <SQLObject, SQLBlockStatement>(parentCtx->object))
      {
        SQLBlockStatement_ptr block = std::dynamic_pointer_cast<SQLBlockStatement>(parentCtx->object);
        SQLParameter_ptr parameter = block->findParameter(hash);
        if (parameter != nullptr)
        {
          x->setResolvedParameter(parameter);
          return;
        }
      }
      else if (instanceof <SQLObject, SQLCreateProcedureStatement>(parentCtx->object))
      {
        SQLCreateProcedureStatement_ptr createProc = std::dynamic_pointer_cast<SQLCreateProcedureStatement>(parentCtx->object);
        SQLParameter_ptr parameter = createProc->findParameter(hash);
        if (parameter != nullptr)
        {
          x->setResolvedParameter(parameter);
          return;
        }
      }
    }
  }

  if (x->getResolvedColumnObject() == nullptr && instanceof <SQLObject, SQLSelectQueryBlock>(ctx->object))
  {
    SQLSelectQueryBlock_ptr queryBlock = std::dynamic_pointer_cast<SQLSelectQueryBlock>(ctx->object);
    BOOL_ptr having = BOOL::FALSE;
    for (SQLObject_ptr current = x, parent = x->getParent(); parent != nullptr; current = parent, parent = parent->getParent())
    {
      if (instanceof <SQLObject, SQLSelectGroupByClause>(parent) && parent->getParent() == queryBlock)
      {
        SQLSelectGroupByClause_ptr groupBy = std::dynamic_pointer_cast<SQLSelectGroupByClause>(parent);
        if (current == groupBy->getHaving())
        {
          having = BOOL::TRUE;
        }
        break;
      }
    }
    if (having)
    {
      SQLSelectItem_ptr selectItem = queryBlock->findSelectItem(x->hashCode64());
      if (selectItem != nullptr)
      {
        x->setResolvedColumn(selectItem);
      }
    }
  }
}

void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLPropertyExpr_ptr x)
{
  SchemaResolveVisitor_Context_ptr ctx = visitor->getContext();
  if (ctx == nullptr)
  {
    return;
  }

  long owner_hash = 0;
  {
    SQLExpr_ptr ownerObj = x->getOwner();
    if (instanceof <SQLExpr, SQLIdentifierExpr>(ownerObj))
    {
      SQLIdentifierExpr_ptr owner = std::dynamic_pointer_cast<SQLIdentifierExpr>(ownerObj);
      owner_hash = owner->nameHashCode64();
    }
    else if (instanceof <SQLExpr, SQLPropertyExpr>(ownerObj))
    {
      owner_hash = (std::dynamic_pointer_cast<SQLPropertyExpr>(ownerObj))->hashCode64();
    }
  }

  SQLTableSource_ptr tableSource = nullptr;
  SQLTableSource_ptr ctxTable = ctx->getTableSource();

  if (ctxTable != nullptr)
  {
    tableSource = ctxTable->findTableSource(owner_hash);
  }

  if (tableSource == nullptr)
  {
    SQLTableSource_ptr ctxFrom = ctx->getFrom();
    if (ctxFrom != nullptr)
    {
      tableSource = ctxFrom->findTableSource(owner_hash);
    }
  }

  if (tableSource == nullptr)
  {
    for (SchemaResolveVisitor_Context_ptr parentCtx = ctx;
         parentCtx != nullptr;
         parentCtx = parentCtx->parent)
    {
      SQLTableSource_ptr parentCtxTable = parentCtx->getTableSource();

      if (parentCtxTable != nullptr)
      {
        tableSource = parentCtxTable->findTableSource(owner_hash);
        if (tableSource == nullptr)
        {
          SQLTableSource_ptr ctxFrom = parentCtx->getFrom();
          if (ctxFrom != nullptr)
          {
            tableSource = ctxFrom->findTableSource(owner_hash);
          }
        }

        if (tableSource != nullptr)
        {
          break;
        }
      }
      else
      {
        if (instanceof <SQLObject, SQLBlockStatement>(parentCtx->object))
        {
          SQLBlockStatement_ptr block = std::dynamic_pointer_cast<SQLBlockStatement>(parentCtx->object);
          SQLParameter_ptr parameter = block->findParameter(owner_hash);
          if (parameter != nullptr)
          {
            x->setResolvedOwnerObject(std::dynamic_pointer_cast<SQLObject>(parameter));
            return;
          }
        }
        else if (instanceof <SQLObject, SQLMergeStatement>(parentCtx->object))
        {
          SQLMergeStatement_ptr mergeStatement = std::dynamic_pointer_cast<SQLMergeStatement>(parentCtx->object);
          SQLTableSource_ptr into = mergeStatement->getInto();
          if (instanceof <SQLTableSource, SQLSubqueryTableSource>(into) && into->aliasHashCode64() == owner_hash)
          {
            x->setResolvedOwnerObject(into);
          }
        }

        SQLDeclareItem_ptr declareItem = parentCtx->findDeclare(owner_hash);
        if (declareItem != nullptr)
        {
          SQLObject_ptr resolvedObject = declareItem->getResolvedObject();
          if (instanceof <SQLObject, SQLCreateProcedureStatement>(resolvedObject) ||
              instanceof <SQLObject, SQLCreateFunctionStatement>(resolvedObject) ||
              instanceof <SQLObject, SQLTableSource>(resolvedObject))
          {
            x->setResolvedOwnerObject(resolvedObject);
          }
          break;
        }
      }
    }
  }

  if (tableSource != nullptr)
  {
    x->setResolvedTableSource(tableSource);
    SQLObject_ptr column = tableSource->resolveColum(x->nameHashCode64());
    if (instanceof <SQLObject, SQLColumnDefinition>(column))
    {
      x->setResolvedColumn(std::dynamic_pointer_cast<SQLColumnDefinition>(column));
    }
    else if (instanceof <SQLObject, SQLSelectItem>(column))
    {
      x->setResolvedColumn(std::dynamic_pointer_cast<SQLSelectItem>(column));
    }
  }
}

void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLBinaryOpExpr_ptr x)
{
  SQLBinaryOperator_ptr op = x->getOperator();
  SQLExpr_ptr left = x->getLeft();

  if ((op->name == SQLBinaryOperator::BooleanAnd.name ||
       op->name == SQLBinaryOperator::BooleanOr.name) &&
      instanceof <SQLExpr, SQLBinaryOpExpr>(left) &&
                     (std::dynamic_pointer_cast<SQLBinaryOpExpr>(left))->getOperator()->name == op->name)
  {
    SQLExpr_list_ptr groupList = SQLBinaryOpExpr::split(x, op);
    auto it_groupList = groupList->begin();
    for (int i = 0; i < groupList->size(); i++)
    {
      std::advance(it_groupList, i);
      SQLExpr_ptr item = *it_groupList;
      item->accept(visitor);
    }
    return;
  }

  if (left != nullptr)
  {
    if (instanceof <SQLExpr, SQLBinaryOpExpr>(left))
    {
      resolve(visitor, std::dynamic_pointer_cast<SQLBinaryOpExpr>(left));
    }
    else
    {
      left->accept(visitor);
    }
  }

  SQLExpr_ptr right = x->getRight();
  if (right != nullptr)
  {
    right->accept(visitor);
  }
}

SQLTableSource_ptr SchemaResolveVisitorFactory::unwrapAlias(SchemaResolveVisitor_Context_ptr ctx, SQLTableSource_ptr tableSource, long identHash)
{
  if (ctx == nullptr)
  {
    return tableSource;
  }

  if (instanceof <SQLObject, SQLDeleteStatement>(ctx->object) && (ctx->getTableSource() == nullptr || tableSource == ctx->getTableSource()) && ctx->getFrom() != nullptr)
  {
    SQLTableSource_ptr found = ctx->getFrom()->findTableSource(identHash);
    if (found != nullptr)
    {
      return found;
    }
  }

  for (SchemaResolveVisitor_Context_ptr parentCtx = ctx;
       parentCtx != nullptr;
       parentCtx = parentCtx->parent)
  {
    SQLWithSubqueryClause_ptr with = nullptr;
    if (instanceof <SQLObject, SQLSelect>(parentCtx->object))
    {
      SQLSelect_ptr select = std::dynamic_pointer_cast<SQLSelect>(parentCtx->object);
      with = select->getWithSubQuery();
    }
    else if (instanceof <SQLObject, SQLDeleteStatement>(parentCtx->object))
    {
      SQLDeleteStatement_ptr delete_ = std::dynamic_pointer_cast<SQLDeleteStatement>(parentCtx->object);
      with = delete_->getWith();
    }
    else if (instanceof <SQLObject, SQLInsertStatement>(parentCtx->object))
    {
      SQLInsertStatement_ptr insertStmt = std::dynamic_pointer_cast<SQLInsertStatement>(parentCtx->object);
      with = insertStmt->getWith();
    }
    else if (instanceof <SQLObject, SQLUpdateStatement>(parentCtx->object))
    {
      SQLUpdateStatement_ptr updateStmt = std::dynamic_pointer_cast<SQLUpdateStatement>(parentCtx->object);
      with = updateStmt->getWith();
    }

    if (with != nullptr)
    {
      SQLWithSubqueryClause_Entry_ptr entry = with->findEntry(identHash);
      if (entry != nullptr)
      {
        return entry;
      }
    }
  }
  return tableSource;
}

void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLSelectQueryBlock_ptr x)
{
  SchemaResolveVisitor_Context_ptr ctx = visitor->createContext(x);
  if (ctx != nullptr && ctx->level >= 32)
  {
    return;
  }

  SQLTableSource_ptr from = x->getFrom();

  if (from != nullptr)
  {
    ctx->setTableSource(from);

    string_ptr fromClass = from->getClass();
    if (fromClass->c_str() == "SQLExprTableSource")
    {
      visitor->visit(std::dynamic_pointer_cast<SQLExprTableSource>(from));
    }
    else
    {
      from->accept(visitor);
    }
  }
  // else if (x->getParent() != nullptr &&
  // instanceof<SQLObject,HiveInsert>(x->getParent()->getParent())   &&
  //  instanceof<SQLObject,HiveMultiInsertStatement>(x->getParent()->getParent()->getParent() ) )
  // {
  //   HiveMultiInsertStatement insert = (HiveMultiInsertStatement)x->getParent().getParent().getParent();
  //   if (insert.getFrom() instanceof SQLExprTableSource_ptr)
  //   {
  //     from = insert.getFrom();
  //     ctx->setTableSource(from);
  //   }
  // }

  SQLSelectItem_list_ptr selectList = x->getSelectList();
  SQLSelectItem_list_ptr columns = std::make_shared<std::list<SQLSelectItem_ptr>>();
  auto it_selectList = selectList->begin();
  for (int i = selectList->size() - 1; i >= 0; i--)
  {
    std::advance(it_selectList, i);
    SQLSelectItem_ptr selectItem = *it_selectList;
    SQLExpr_ptr expr = selectItem->getExpr();
    if (instanceof <SQLExpr, SQLAllColumnExpr>(expr))
    {
      SQLAllColumnExpr_ptr allColumnExpr = std::dynamic_pointer_cast<SQLAllColumnExpr>(expr);
      allColumnExpr->setResolvedTableSource(from);

      visitor->visit(allColumnExpr);

      if (visitor->isEnabled(SchemaResolveVisitor_Option::ResolveAllColumn))
      {
        extractColumns(visitor, from, nullptr, columns);
      }
    }
    else if (instanceof <SQLExpr, SQLPropertyExpr>(expr))
    {
      SQLPropertyExpr_ptr propertyExpr = std::dynamic_pointer_cast<SQLPropertyExpr>(expr);
      visitor->visit(propertyExpr);

      string_ptr ownerName = propertyExpr->getOwnernName();
      if (propertyExpr->getName()->c_str() == "*")
      {
        if (visitor->isEnabled(SchemaResolveVisitor_Option::ResolveAllColumn))
        {
          SQLTableSource_ptr tableSource = x->findTableSource(ownerName);
          extractColumns(visitor, tableSource, ownerName, columns);
        }
      }

      SQLColumnDefinition_ptr column = std::dynamic_pointer_cast<SQLColumnDefinition>(propertyExpr->getResolvedColumn());
      if (column != nullptr)
      {
        continue;
      }
      SQLTableSource_ptr tableSource = x->findTableSource(propertyExpr->getOwnernName());
      if (tableSource != nullptr)
      {
        column = tableSource->findColumn(propertyExpr->nameHashCode64());
        if (column != nullptr)
        {
          propertyExpr->setResolvedColumn(column);
        }
      }
    }
    else if (instanceof <SQLExpr, SQLIdentifierExpr>(expr))
    {
      SQLIdentifierExpr_ptr identExpr = std::dynamic_pointer_cast<SQLIdentifierExpr>(expr);
      visitor->visit(identExpr);

      long name_hash = identExpr->nameHashCode64();

      SQLColumnDefinition_ptr column = std::dynamic_pointer_cast<SQLColumnDefinition>(identExpr->getResolvedColumn());
      if (column != nullptr)
      {
        continue;
      }
      if (from == nullptr)
      {
        continue;
      }
      column = from->findColumn(name_hash);
      if (column != nullptr)
      {
        identExpr->setResolvedColumn(column);
      }
    }
    else
    {
      expr->accept(visitor);
    }

    if (columns->size() > 0)
    {
      for (SQLSelectItem_ptr column : *columns)
      {
        column->setParent(x);
        column->getExpr()->accept(visitor);
      }

      // selectList.remove(i);
      if (it_selectList != selectList->end())
        selectList->erase(it_selectList);
      // selectList.addAll(i, columns);
      SQLSelectItem_list_ptr selectList_tmp = std::make_shared<std::list<SQLSelectItem_ptr>>();
      int j = 0;
      for (auto select_list : *selectList)
      {
        selectList_tmp->push_back(select_list);
        if (j == i)
        {
          for (auto column : *columns)
          {
            selectList_tmp->push_back(column);
          }
        }
        j++;
      }
      columns->clear();
    }
  }

  SQLExprTableSource_ptr into = x->getInto();
  if (into != nullptr)
  {
    visitor->visit(into);
  }

  SQLExpr_ptr where = x->getWhere();
  if (where != nullptr)
  {
    if (instanceof <SQLExpr, SQLBinaryOpExpr>(where))
    {
      SQLBinaryOpExpr_ptr binaryOpExpr = std::dynamic_pointer_cast<SQLBinaryOpExpr>(where);
      resolveExpr(visitor, binaryOpExpr->getLeft());
      resolveExpr(visitor, binaryOpExpr->getRight());
    }
    else if (instanceof <SQLExpr, SQLBinaryOpExprGroup>(where))
    {
      SQLBinaryOpExprGroup_ptr binaryOpExprGroup = std::dynamic_pointer_cast<SQLBinaryOpExprGroup>(where);
      for (SQLExpr_ptr item : *binaryOpExprGroup->getItems())
      {
        if (instanceof <SQLExpr, SQLBinaryOpExpr>(item))
        {
          SQLBinaryOpExpr_ptr binaryOpExpr = std::dynamic_pointer_cast<SQLBinaryOpExpr>(item);
          resolveExpr(visitor, binaryOpExpr->getLeft());
          resolveExpr(visitor, binaryOpExpr->getRight());
        }
        else
        {
          item->accept(visitor);
        }
      }
    }
    else
    {
      where->accept(visitor);
    }
  }

  SQLExpr_ptr startWith = x->getStartWith();
  if (startWith != nullptr)
  {
    startWith->accept(visitor);
  }

  SQLExpr_ptr connectBy = x->getConnectBy();
  if (connectBy != nullptr)
  {
    connectBy->accept(visitor);
  }

  SQLSelectGroupByClause_ptr groupBy = x->getGroupBy();
  if (groupBy != nullptr)
  {
    groupBy->accept(visitor);
  }

  SQLWindow_list_ptr windows = x->getWindows();
  if (windows != nullptr)
  {
    for (SQLWindow_ptr window : *windows)
    {
      window->accept(visitor);
    }
  }

  SQLOrderBy_ptr orderBy = x->getOrderBy();
  if (orderBy != nullptr)
  {
    for (SQLSelectOrderByItem_ptr orderByItem : *orderBy->getItems())
    {
      SQLExpr_ptr orderByItemExpr = orderByItem->getExpr();

      if (instanceof <SQLExpr, SQLIdentifierExpr>(orderByItemExpr))
      {
        SQLIdentifierExpr_ptr orderByItemIdentExpr = std::dynamic_pointer_cast<SQLIdentifierExpr>(orderByItemExpr);
        long hash = orderByItemIdentExpr->nameHashCode64();
        SQLSelectItem_ptr selectItem = x->findSelectItem(hash);

        if (selectItem != nullptr)
        {
          orderByItem->setResolvedSelectItem(selectItem);

          SQLExpr_ptr selectItemExpr = selectItem->getExpr();
          if (instanceof <SQLExpr, SQLIdentifierExpr>(selectItemExpr))
          {
            orderByItemIdentExpr->setResolvedTableSource((std::dynamic_pointer_cast<SQLIdentifierExpr>(selectItemExpr))->getResolvedTableSource());
            orderByItemIdentExpr->setResolvedColumn(std::dynamic_pointer_cast<SQLColumnDefinition>((std::dynamic_pointer_cast<SQLIdentifierExpr>(selectItemExpr))->getResolvedColumn()));
          }
          else if (instanceof <SQLExpr, SQLPropertyExpr>(selectItemExpr))
          {
            orderByItemIdentExpr->setResolvedTableSource((std::dynamic_pointer_cast<SQLPropertyExpr>(selectItemExpr))->getResolvedTableSource());
            orderByItemIdentExpr->setResolvedColumn(std::dynamic_pointer_cast<SQLColumnDefinition>((std::dynamic_pointer_cast<SQLPropertyExpr>(selectItemExpr))->getResolvedColumn()));
          }
          continue;
        }
      }

      orderByItemExpr->accept(visitor);
    }
  }

  int forUpdateOfSize = x->getForUpdateOfSize();
  if (forUpdateOfSize > 0)
  {
    for (SQLExpr_ptr sqlExpr : *x->getForUpdateOf())
    {
      sqlExpr->accept(visitor);
    }
  }

  SQLSelectOrderByItem_list_ptr distributeBy = x->getDistributeBy();
  if (distributeBy != nullptr)
  {
    for (SQLSelectOrderByItem_ptr item : *distributeBy)
    {
      item->accept(visitor);
    }
  }

  SQLSelectOrderByItem_list_ptr sortBy = x->getSortBy();
  if (sortBy != nullptr)
  {
    for (SQLSelectOrderByItem_ptr item : *sortBy)
    {
      item->accept(visitor);
    }
  }

  visitor->popContext();
}

void SchemaResolveVisitorFactory::extractColumns(
    SchemaResolveVisitor_ptr visitor,
    SQLTableSource_ptr from,
    string_ptr ownerName,
    SQLSelectItem_list_ptr columns)
{
  if (instanceof <SQLTableSource, SQLExprTableSource>(from))
  {
    SQLExpr_ptr expr = (std::dynamic_pointer_cast<SQLExprTableSource>(from))->getExpr();

    SchemaRepository_ptr repository = visitor->getRepository();
    if (repository == nullptr)
    {
      return;
    }

    string_ptr alias = from->getAlias();

    SchemaObject_ptr table = repository->findTable(std::dynamic_pointer_cast<SQLExprTableSource>(from));
    if (table != nullptr)
    {
      SQLCreateTableStatement_ptr createTableStmt = std::dynamic_pointer_cast<SQLCreateTableStatement>(table->getStatement());
      for (SQLTableElement_ptr e : *createTableStmt->getTableElementList())
      {
        if (instanceof <SQLTableElement, SQLColumnDefinition>(e))
        {
          SQLColumnDefinition_ptr column = std::dynamic_pointer_cast<SQLColumnDefinition>(e);

          if (alias != nullptr)
          {
            SQLPropertyExpr_ptr name = SQLPropertyExpr_ptr(new SQLPropertyExpr(alias, column->getName()->getSimpleName()));
            name->setResolvedColumn(column);
            columns->push_back(SQLSelectItem_ptr(new SQLSelectItem(name)));
          }
          else if (ownerName != nullptr)
          {
            SQLPropertyExpr_ptr name = SQLPropertyExpr_ptr(new SQLPropertyExpr(ownerName, column->getName()->getSimpleName()));
            name->setResolvedColumn(column);
            columns->push_back(SQLSelectItem_ptr(new SQLSelectItem(name)));
          }
          else if (instanceof <SQLObject, SQLJoinTableSource>(from->getParent()) &&
                   instanceof <SQLTableSource, SQLExprTableSource>(from) &&
                   instanceof <SQLExpr, SQLName>(expr))
          {
            string_ptr tableName = expr->toString();
            SQLPropertyExpr_ptr name = SQLPropertyExpr_ptr(new SQLPropertyExpr(tableName, column->getName()->getSimpleName()));
            name->setResolvedColumn(column);
            columns->push_back(SQLSelectItem_ptr(new SQLSelectItem(name)));
          }
          else
          {
            SQLIdentifierExpr_ptr name = std::dynamic_pointer_cast<SQLIdentifierExpr>(column->getName()->clone());
            name->setResolvedColumn(column);
            columns->push_back(SQLSelectItem_ptr(new SQLSelectItem(name)));
          }
        }
      }
      return;
    }

    if (instanceof <SQLExpr, SQLIdentifierExpr>(expr))
    {
      SQLTableSource_ptr resolvedTableSource = (std::dynamic_pointer_cast<SQLIdentifierExpr>(expr))->getResolvedTableSource();
      if (instanceof <SQLTableSource, SQLWithSubqueryClause_Entry>(resolvedTableSource))
      {
        SQLWithSubqueryClause_Entry_ptr entry = std::dynamic_pointer_cast<SQLWithSubqueryClause_Entry>(resolvedTableSource);
        SQLSelect_ptr select = (std::dynamic_pointer_cast<SQLWithSubqueryClause_Entry>(resolvedTableSource))->getSubQuery();
        SQLSelectQueryBlock_ptr firstQueryBlock = select->getFirstQueryBlock();
        if (firstQueryBlock != nullptr)
        {
          for (SQLSelectItem_ptr item : *firstQueryBlock->getSelectList())
          {
            string_ptr itemAlias = item->computeAlias();
            if (itemAlias != nullptr)
            {
              SQLIdentifierExpr_ptr columnExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(itemAlias));
              columnExpr->setResolvedColumn(item);
              columns->push_back(SQLSelectItem_ptr(new SQLSelectItem(columnExpr)));
            }
          }
        }
      }
    }
  }
  else if (instanceof <SQLTableSource, SQLJoinTableSource>(from))
  {
    SQLJoinTableSource_ptr join = std::dynamic_pointer_cast<SQLJoinTableSource>(from);
    extractColumns(visitor, join->getLeft(), ownerName, columns);
    extractColumns(visitor, join->getRight(), ownerName, columns);
  }
  else if (instanceof <SQLTableSource, SQLSubqueryTableSource>(from))
  {
    SQLSelectQueryBlock_ptr subQuery = (std::dynamic_pointer_cast<SQLSubqueryTableSource>(from))->getSelect()->getQueryBlock();
    if (subQuery == nullptr)
    {
      return;
    }
    SQLSelectItem_list_ptr subSelectList = subQuery->getSelectList();
    for (SQLSelectItem_ptr subSelectItem : *subSelectList)
    {
      if (subSelectItem->getAlias() != nullptr)
      {
        continue;
      }

      if (!(instanceof <SQLExpr, SQLName>(subSelectItem->getExpr())))
      {
        return; // skip
      }
    }

    for (SQLSelectItem_ptr subSelectItem : *subSelectList)
    {
      string_ptr alias = subSelectItem->computeAlias();
      columns->push_back(SQLSelectItem_ptr(new SQLSelectItem(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(alias)))));
    }
  }
  else if (instanceof <SQLTableSource, SQLUnionQueryTableSource>(from))
  {
    SQLSelectQueryBlock_ptr firstQueryBlock = (std::dynamic_pointer_cast<SQLUnionQueryTableSource>(from))->getUnion()->getFirstQueryBlock();
    if (firstQueryBlock == nullptr)
    {
      return;
    }

    SQLSelectItem_list_ptr subSelectList = firstQueryBlock->getSelectList();
    for (SQLSelectItem_ptr subSelectItem : *subSelectList)
    {
      if (subSelectItem->getAlias() != nullptr)
      {
        continue;
      }

      if (!(instanceof <SQLExpr, SQLName>(subSelectItem->getExpr())))
      {
        return; // skip
      }
    }

    for (SQLSelectItem_ptr subSelectItem : *subSelectList)
    {
      string_ptr alias = subSelectItem->computeAlias();
      columns->push_back(SQLSelectItem_ptr(new SQLSelectItem(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(alias)))));
    }
  }
}

void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLAllColumnExpr_ptr x)
{
  SQLTableSource_ptr tableSource = x->getResolvedTableSource();

  if (tableSource == nullptr)
  {
    SQLSelectQueryBlock_ptr queryBlock = nullptr;
    for (SQLObject_ptr parent = x->getParent(); parent != nullptr; parent = parent->getParent())
    {
      if (instanceof <SQLObject, SQLTableSource>(parent))
      {
        return;
      }
      if (instanceof <SQLObject, SQLSelectQueryBlock>(parent))
      {
        queryBlock = std::dynamic_pointer_cast<SQLSelectQueryBlock>(parent);
        break;
      }
    }

    if (queryBlock == nullptr)
    {
      return;
    }

    SQLTableSource_ptr from = queryBlock->getFrom();
    if (from == nullptr || instanceof <SQLTableSource, SQLJoinTableSource>(from))
    {
      return;
    }

    x->setResolvedTableSource(from);
    tableSource = from;
  }

  if (instanceof <SQLTableSource, SQLExprTableSource>(tableSource))
  {
    SQLExpr_ptr expr = (std::dynamic_pointer_cast<SQLExprTableSource>(tableSource))->getExpr();
    if (instanceof <SQLExpr, SQLIdentifierExpr>(expr))
    {
      SQLTableSource_ptr resolvedTableSource = (std::dynamic_pointer_cast<SQLIdentifierExpr>(expr))->getResolvedTableSource();
      if (resolvedTableSource != nullptr)
      {
        x->setResolvedTableSource(resolvedTableSource);
      }
    }
  }
}

void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr v, SQLMethodInvokeExpr_ptr x)
{
  SQLExpr_ptr owner = x->getOwner();
  if (owner != nullptr)
  {
    resolveExpr(v, owner);
  }

  for (SQLExpr_ptr arg : *x->getArguments())
  {
    resolveExpr(v, arg);
  }

  SQLExpr_ptr from = x->getFrom();
  if (from != nullptr)
  {
    resolveExpr(v, from);
  }

  SQLExpr_ptr using_ = x->getUsing();
  if (using_ != nullptr)
  {
    resolveExpr(v, using_);
  }

  SQLExpr_ptr _for = x->getFor();
  if (_for != nullptr)
  {
    resolveExpr(v, _for);
  }

  long nameHash = x->methodNameHashCode64();
  SchemaRepository_ptr repository = v->getRepository();
  if (repository != nullptr)
  {
    SQLDataType_ptr dataType = repository->findFuntionReturnType(nameHash);
    if (dataType != nullptr)
    {
      x->setResolvedReturnDataType(dataType);
    }
  }
}

void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLSelect_ptr x)
{
  SchemaResolveVisitor_Context_ptr ctx = visitor->createContext(x);

  SQLWithSubqueryClause_ptr with = x->getWithSubQuery();
  if (with != nullptr)
  {
    visitor->visit(with);
  }

  SQLSelectQuery_ptr query = x->getQuery();
  if (query != nullptr)
  {
    if (instanceof <SQLSelectQuery, SQLSelectQueryBlock>(query))
    {
      visitor->visit(std::dynamic_pointer_cast<SQLSelectQueryBlock>(query));
    }
    else
    {
      query->accept(visitor);
    }
  }

  SQLSelectQueryBlock_ptr queryBlock = x->getFirstQueryBlock();

  SQLOrderBy_ptr orderBy = x->getOrderBy();
  if (orderBy != nullptr)
  {
    for (SQLSelectOrderByItem_ptr orderByItem : *orderBy->getItems())
    {
      SQLExpr_ptr orderByItemExpr = orderByItem->getExpr();

      if (instanceof <SQLExpr, SQLIdentifierExpr>(orderByItemExpr))
      {
        SQLIdentifierExpr_ptr orderByItemIdentExpr = std::dynamic_pointer_cast<SQLIdentifierExpr>(orderByItemExpr);
        long hash = orderByItemIdentExpr->nameHashCode64();

        SQLSelectItem_ptr selectItem = nullptr;
        if (queryBlock != nullptr)
        {
          selectItem = queryBlock->findSelectItem(hash);
        }

        if (selectItem != nullptr)
        {
          orderByItem->setResolvedSelectItem(selectItem);

          SQLExpr_ptr selectItemExpr = selectItem->getExpr();
          if (instanceof <SQLExpr, SQLIdentifierExpr>(selectItemExpr))
          {
            orderByItemIdentExpr->setResolvedTableSource((std::dynamic_pointer_cast<SQLIdentifierExpr>(selectItemExpr))->getResolvedTableSource());
            orderByItemIdentExpr->setResolvedColumn(std::dynamic_pointer_cast<SQLColumnDefinition>((std::dynamic_pointer_cast<SQLIdentifierExpr>(selectItemExpr))->getResolvedColumn()));
          }
          else if (instanceof <SQLExpr, SQLPropertyExpr>(selectItemExpr))
          {
            orderByItemIdentExpr->setResolvedTableSource((std::dynamic_pointer_cast<SQLPropertyExpr>(selectItemExpr))->getResolvedTableSource());
            orderByItemIdentExpr->setResolvedColumn(std::dynamic_pointer_cast<SQLColumnDefinition>((std::dynamic_pointer_cast<SQLPropertyExpr>(selectItemExpr))->getResolvedColumn()));
          }
          continue;
        }
      }

      orderByItemExpr->accept(visitor);
    }
  }

  visitor->popContext();
}

void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLWithSubqueryClause_ptr x)
{
  SQLWithSubqueryClause_Entry_list_ptr entries = x->getEntries();
  SchemaResolveVisitor_Context_ptr context = visitor->getContext();
  for (SQLWithSubqueryClause_Entry_ptr entry : *entries)
  {
    SQLSelect_ptr query = entry->getSubQuery();
    if (query != nullptr)
    {
      visitor->visit(query);

      long alias_hash = entry->aliasHashCode64();
      if (context != nullptr && alias_hash != 0)
      {
        context->addTableSource(alias_hash, entry);
      }
    }
    else if (entry->getExpr() != nullptr)
    {
      entry->getExpr()->accept(visitor);
    }
    else
    {
      SQLStatement_ptr returningStatement = entry->getReturningStatement();
      if (returningStatement != nullptr)
      {
        returningStatement->accept(visitor);
      }
    }
  }
}

void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLExprTableSource_ptr x)
{
  SQLExpr_ptr expr = x->getExpr();

  SQLExpr_ptr annFeature = nullptr;
  if (instanceof <SQLExpr, SQLMethodInvokeExpr>(expr))
  {
    SQLMethodInvokeExpr_ptr func = std::dynamic_pointer_cast<SQLMethodInvokeExpr>(expr);
    if (func->methodNameHashCode64() == FnvHash::Constants::ANN)
    {
      auto it_getArguments = func->getArguments()->begin();
      expr = *it_getArguments;

      std::advance(it_getArguments, 1);
      annFeature = *it_getArguments;
      if (instanceof <SQLExpr, SQLIdentifierExpr>(annFeature))
      {
        (std::dynamic_pointer_cast<SQLIdentifierExpr>(annFeature))->setResolvedTableSource(x);
      }
      else if (instanceof <SQLExpr, SQLPropertyExpr>(annFeature))
      {
        (std::dynamic_pointer_cast<SQLPropertyExpr>(annFeature))->setResolvedTableSource(x);
      }
    }
  }

  if (instanceof <SQLExpr, SQLName>(expr))
  {
    if (x->getSchemaObject() != nullptr)
    {
      return;
    }

    SQLIdentifierExpr_ptr identifierExpr = nullptr;

    if (instanceof <SQLExpr, SQLIdentifierExpr>(expr))
    {
      identifierExpr = std::dynamic_pointer_cast<SQLIdentifierExpr>(expr);
    }
    else if (instanceof <SQLExpr, SQLPropertyExpr>(expr))
    {
      SQLExpr_ptr owner = (std::dynamic_pointer_cast<SQLPropertyExpr>(expr))->getOwner();
      if (instanceof <SQLExpr, SQLIdentifierExpr>(owner))
      {
        identifierExpr = std::dynamic_pointer_cast<SQLIdentifierExpr>(owner);
      }
    }

    if (identifierExpr != nullptr)
    {
      checkParameter(visitor, identifierExpr);

      SQLTableSource_ptr tableSource = unwrapAlias(visitor->getContext(), nullptr, identifierExpr->nameHashCode64());
      // if (tableSource == nullptr && instanceof<SQLObject,HiveMultiInsertStatement>(x->getParent())  )
      // {
      //   SQLWithSubqueryClause_ptr with = ((HiveMultiInsertStatement)x->getParent()).getWith();
      //   if (with != nullptr)
      //   {
      //     SQLWithSubqueryClause_Entry_ptr entry = with.findEntry(identifierExpr.nameHashCode64());
      //     tableSource = entry;
      //   }
      // }

      if (tableSource != nullptr)
      {
        identifierExpr->setResolvedTableSource(tableSource);
        return;
      }
    }

    SchemaRepository_ptr repository = visitor->getRepository();
    if (repository != nullptr)
    {
      SchemaObject_ptr table = repository->findTable(std::dynamic_pointer_cast<SQLName>(expr));
      if (table != nullptr)
      {
        x->setSchemaObject(table);

        if (annFeature != nullptr)
        {
          if (instanceof <SQLExpr, SQLIdentifierExpr>(annFeature))
          {
            SQLIdentifierExpr_ptr identExpr = std::dynamic_pointer_cast<SQLIdentifierExpr>(annFeature);
            SQLColumnDefinition_ptr column = table->findColumn(identExpr->nameHashCode64());
            if (column != nullptr)
            {
              identExpr->setResolvedColumn(column);
            }
          }
        }
        return;
      }

      SchemaObject_ptr view = repository->findView(std::dynamic_pointer_cast<SQLName>(expr));
      if (view != nullptr)
      {
        x->setSchemaObject(view);
        return;
      }
    }
    return;
  }

  if (instanceof <SQLExpr, SQLMethodInvokeExpr>(expr))
  {
    visitor->visit(std::dynamic_pointer_cast<SQLMethodInvokeExpr>(expr));
    return;
  }

  if (instanceof <SQLExpr, SQLQueryExpr>(expr))
  {
    SQLSelect_ptr select = (std::dynamic_pointer_cast<SQLQueryExpr>(expr))->getSubQuery();

    visitor->visit(select);

    SQLSelectQueryBlock_ptr queryBlock = select->getQueryBlock();
    if (queryBlock != nullptr && instanceof <SQLExpr, SQLIdentifierExpr>(annFeature))
    {
      SQLIdentifierExpr_ptr identExpr = std::dynamic_pointer_cast<SQLIdentifierExpr>(annFeature);
      SQLObject_ptr columnDef = queryBlock->resolveColum(identExpr->nameHashCode64());
      if (instanceof <SQLObject, SQLColumnDefinition>(columnDef))
      {
        identExpr->setResolvedColumn(std::dynamic_pointer_cast<SQLColumnDefinition>(columnDef));
      }
      else if (instanceof <SQLObject, SQLSelectItem>(columnDef))
      {
        identExpr->setResolvedColumn(std::dynamic_pointer_cast<SQLSelectItem>(columnDef));
      }
    }
    // if (queryBlock.findColumn())
    return;
  }

  expr->accept(visitor);
}

void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLAlterTableStatement_ptr x)
{
  SchemaResolveVisitor_Context_ptr ctx = visitor->createContext(std::dynamic_pointer_cast<SQLObject>(x));

  SQLTableSource_ptr tableSource = x->getTableSource();
  ctx->setTableSource(tableSource);

  for (SQLAlterTableItem_ptr item : *x->getItems())
  {
    item->accept(visitor);
  }

  visitor->popContext();
}

// void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLMergeStatement_ptr x)
// {
//   SchemaResolveVisitor_Context_ptr ctx = visitor->createContext(x);

//   SQLTableSource_ptr into = x->getInto();
//   if (into instanceof SQLExprTableSource_ptr)
//   {
//     ctx->setTableSource(into);
//   }
//   else
//   {
//     into->accept(visitor);
//   }

//   SQLTableSource_ptr using_ = x->getUsing();
//   if (using_ != nullptr)
//   {
//     using_->accept(visitor);
//     ctx->setFrom(using_);
//   }

//   SQLExpr_ptr on = x->getOn();
//   if (on != nullptr)
//   {
//     on->accept(visitor);
//   }

//   SQLMergeStatement.MergeUpdateClause updateClause = x->getUpdateClause();
//   if (updateClause != nullptr)
//   {
//     for (SQLUpdateSetItem item : updateClause.getItems())
//     {
//       SQLExpr_ptr column = item.getColumn();

//       if (column instanceof SQLIdentifierExpr_ptr)
//       {
//         ((SQLIdentifierExpr_ptr)column).setResolvedTableSource(into);
//       }
//       else if (column instanceof SQLPropertyExpr)
//       {
//         ((SQLPropertyExpr)column).setResolvedTableSource(into);
//       }
//       else
//       {
//         column->accept(visitor);
//       }

//       SQLExpr_ptr value = item.getValue();
//       if (value != nullptr)
//       {
//         value->accept(visitor);
//       }
//     }

//     SQLExpr_ptr where = updateClause.getWhere();
//     if (where != nullptr)
//     {
//       where->accept(visitor);
//     }

//     SQLExpr_ptr deleteWhere = updateClause.getDeleteWhere();
//     if (deleteWhere != nullptr)
//     {
//       deleteWhere->accept(visitor);
//     }
//   }

//   SQLMergeStatement.MergeInsertClause insertClause = x->getInsertClause();
//   if (insertClause != nullptr)
//   {
//     for (SQLExpr_ptr column : insertClause.getColumns())
//     {
//       if (column instanceof SQLIdentifierExpr_ptr)
//       {
//         ((SQLIdentifierExpr_ptr)column).setResolvedTableSource(into);
//       }
//       else if (column instanceof SQLPropertyExpr)
//       {
//         ((SQLPropertyExpr)column).setResolvedTableSource(into);
//       }
//       column->accept(visitor);
//     }
//     for (SQLExpr_ptr value : insertClause.getValues())
//     {
//       value->accept(visitor);
//     }
//     SQLExpr_ptr where = insertClause.getWhere();
//     if (where != nullptr)
//     {
//       where->accept(visitor);
//     }
//   }

//   visitor->popContext();
// }

// void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLCreateFunctionStatement_ptr x)
// {
//   SchemaResolveVisitor_Context_ptr ctx = visitor->createContext(x);

//   {
//     SQLDeclareItem_ptr declareItem = new SQLDeclareItem_ptr(x->getName().clone(), nullptr);
//     declareItem.setResolvedObject(x);

//     SchemaResolveVisitor_Context_ptr parentCtx = visitor->getContext();
//     if (parentCtx != nullptr)
//     {
//       parentCtx->declare(declareItem);
//     }
//     else
//     {
//       ctx->declare(declareItem);
//     }
//   }

//   for (SQLParameter_ptr parameter : x->getParameters())
//   {
//     parameter->accept(visitor);
//   }

//   SQLStatement block = x->getBlock();
//   if (block != nullptr)
//   {
//     block->accept(visitor);
//   }

//   visitor->popContext();
// }

// void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLCreateProcedureStatement_ptr x)
// {
//   SchemaResolveVisitor_Context_ptr ctx = visitor->createContext(x);

//   {
//     SQLDeclareItem_ptr declareItem = new SQLDeclareItem_ptr(x->getName().clone(), nullptr);
//     declareItem.setResolvedObject(x);

//     SchemaResolveVisitor_Context_ptr parentCtx = visitor->getContext();
//     if (parentCtx != nullptr)
//     {
//       parentCtx->declare(declareItem);
//     }
//     else
//     {
//       ctx->declare(declareItem);
//     }
//   }

//   for (SQLParameter_ptr parameter : x->getParameters())
//   {
//     parameter->accept(visitor);
//   }

//   SQLStatement block = x->getBlock();
//   if (block != nullptr)
//   {
//     block->accept(visitor);
//   }

//   visitor->popContext();
// }

// BOOL_ptr SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLIfStatement_ptr x)
// {
//   SchemaResolveVisitor_Context_ptr ctx = visitor->createContext(x);

//   SQLExpr_ptr condition = x->getCondition();
//   if (condition != nullptr)
//   {
//     condition->accept(visitor);
//   }

//   for (SQLStatement stmt : x->getStatements())
//   {
//     stmt->accept(visitor);
//   }

//   for (SQLIfStatement.ElseIf elseIf : x->getElseIfList())
//   {
//     elseIf->accept(visitor);
//   }

//   SQLIfStatement.Else e = x->getElseItem();
//   if (e != nullptr)
//   {
//     e->accept(visitor);
//   }

//   visitor->popContext();
//   return BOOL::FALSE;
// }

void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLBlockStatement_ptr x)
{
  SchemaResolveVisitor_Context_ptr ctx = visitor->createContext(x);

  for (SQLParameter_ptr parameter : *x->getParameters())
  {
    visitor->visit(parameter);
  }

  for (SQLStatement_ptr stmt : *x->getStatementList())
  {
    stmt->accept(visitor);
  }

  SQLStatement_ptr exception = x->getException();
  if (exception != nullptr)
  {
    exception->accept(visitor);
  }

  visitor->popContext();
}

void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLParameter_ptr x)
{
  SQLName_ptr name = x->getName();
  if (instanceof <SQLName, SQLIdentifierExpr>(name))
  {
    (std::dynamic_pointer_cast<SQLIdentifierExpr>(name))->setResolvedParameter(x);
  }

  SQLExpr_ptr expr = x->getDefaultValue();

  SchemaResolveVisitor_Context_ptr ctx = nullptr;
  if (expr != nullptr)
  {
    if (instanceof <SQLExpr, SQLQueryExpr>(expr))
    {
      ctx = visitor->createContext(x);

      SQLSubqueryTableSource_ptr tableSource = SQLSubqueryTableSource_ptr(new SQLSubqueryTableSource((std::dynamic_pointer_cast<SQLQueryExpr>(expr))->getSubQuery()));
      tableSource->setParent(x);
      tableSource->setAlias(x->getName()->getSimpleName());

      ctx->setTableSource(tableSource);
    }

    expr->accept(visitor);
  }

  if (ctx != nullptr)
  {
    visitor->popContext();
  }
}

void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLDeclareItem_ptr x)
{
  SchemaResolveVisitor_Context_ptr ctx = visitor->getContext();
  if (ctx != nullptr)
  {
    ctx->declare(x);
  }

  SQLName_ptr name = x->getName();
  if (instanceof <SQLName, SQLIdentifierExpr>(name))
  {
    (std::dynamic_pointer_cast<SQLIdentifierExpr>(name))->setResolvedDeclareItem(x);
  }
}

void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLOver_ptr x)
{
  SQLName_ptr of = x->getOf();
  SQLOrderBy_ptr orderBy = x->getOrderBy();
  SQLExpr_list_ptr partitionBy = x->getPartitionBy();

  if (of == nullptr // skip if of is not nullptr
      && orderBy != nullptr)
  {
    orderBy->accept(visitor);
  }

  if (partitionBy != nullptr)
  {
    for (SQLExpr_ptr expr : *partitionBy)
    {
      expr->accept(visitor);
    }
  }
}

BOOL_ptr SchemaResolveVisitorFactory::checkParameter(SchemaResolveVisitor_ptr visitor, SQLIdentifierExpr_ptr x)
{
  if (x->getResolvedParameter() != nullptr)
  {
    return BOOL::TRUE;
  }

  SchemaResolveVisitor_Context_ptr ctx = visitor->getContext();
  if (ctx == nullptr)
  {
    return BOOL::FALSE;
  }

  long hash = x->hashCode64();
  for (SchemaResolveVisitor_Context_ptr parentCtx = ctx;
       parentCtx != nullptr;
       parentCtx = parentCtx->parent)
  {
    if (instanceof <SQLObject, SQLBlockStatement>(parentCtx->object))
    {
      SQLBlockStatement_ptr block = std::dynamic_pointer_cast<SQLBlockStatement>(parentCtx->object);
      SQLParameter_ptr parameter = block->findParameter(hash);
      if (parameter != nullptr)
      {
        x->setResolvedParameter(parameter);
        return BOOL::TRUE;
      }
    }

    if (instanceof <SQLObject, SQLCreateProcedureStatement>(parentCtx->object))
    {
      SQLCreateProcedureStatement_ptr createProc = std::dynamic_pointer_cast<SQLCreateProcedureStatement>(parentCtx->object);
      SQLParameter_ptr parameter = createProc->findParameter(hash);
      if (parameter != nullptr)
      {
        x->setResolvedParameter(parameter);
        return BOOL::TRUE;
      }
    }

    if (instanceof <SQLObject, SQLSelect>(parentCtx->object))
    {
      SQLSelect_ptr select = std::dynamic_pointer_cast<SQLSelect>(parentCtx->object);
      SQLWithSubqueryClause_ptr with = select->getWithSubQuery();
      if (with != nullptr)
      {
        SQLWithSubqueryClause_Entry_ptr entry = with->findEntry(hash);
        if (entry != nullptr)
        {
          x->setResolvedTableSource(entry);
          return BOOL::TRUE;
        }
      }

      SchemaRepository_ptr repo = visitor->getRepository();
      if (repo != nullptr)
      {
        SchemaObject_ptr view = repo->findView(x);
        // if (view != nullptr && instanceof<SQLStatement,SQLCreateViewStatement>(view->getStatement())  )
        // {
        //   x->setResolvedOwnerObject(view->getStatement());
        // }
      }
    }

    SQLDeclareItem_ptr declareItem = parentCtx->findDeclare(hash);
    if (declareItem != nullptr)
    {
      x->setResolvedDeclareItem(declareItem);
      break;
    }
  }
  return BOOL::FALSE;
}

// void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLReplaceStatement_ptr x)
// {
//   SchemaResolveVisitor_Context_ptr ctx = visitor->createContext(x);

//   SQLExprTableSource_ptr tableSource = x->getTableSource();
//   ctx->setTableSource(tableSource);
//   visitor->visit(tableSource);

//   for (SQLExpr_ptr column : x->getColumns())
//   {
//     column->accept(visitor);
//   }

//   SQLQueryExpr queryExpr = x->getQuery();
//   if (queryExpr != nullptr)
//   {
//     visitor->visit(queryExpr.getSubQuery());
//   }

//   visitor->popContext();
// }

// void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLFetchStatement_ptr x)
// {
//   resolveExpr(visitor, x->getCursorName());
//   for (SQLExpr_ptr expr : x->getInto())
//   {
//     resolveExpr(visitor, expr);
//   }
// }

void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLForeignKeyConstraint_ptr x)
{
  SchemaRepository_ptr repository = visitor->getRepository();
  SQLObject_ptr parent = x->getParent();

  if (instanceof <SQLObject, SQLCreateTableStatement>(parent))
  {
    SQLCreateTableStatement_ptr createTableStmt = std::dynamic_pointer_cast<SQLCreateTableStatement>(parent);
    SQLTableSource_ptr table = createTableStmt->getTableSource();
    for (SQLName_ptr item : *x->getReferencingColumns())
    {
      SQLIdentifierExpr_ptr columnName = std::dynamic_pointer_cast<SQLIdentifierExpr>(item);
      columnName->setResolvedTableSource(table);

      SQLColumnDefinition_ptr column = createTableStmt->findColumn(columnName->nameHashCode64());
      if (column != nullptr)
      {
        columnName->setResolvedColumn(column);
      }
    }
  }
  // else if (instanceof<SQLObject,SQLAlterTableAddConstraint>(parent)  )
  // {
  //   SQLAlterTableStatement stmt = (SQLAlterTableStatement)parent.getParent();
  //   SQLTableSource_ptr table = stmt.getTableSource();
  //   for (SQLName item : x->getReferencingColumns())
  //   {
  //     SQLIdentifierExpr_ptr columnName = (SQLIdentifierExpr_ptr)item;
  //     columnName.setResolvedTableSource(table);
  //   }
  // }

  if (repository == nullptr)
  {
    return;
  }

  SQLExprTableSource_ptr table = x->getReferencedTable();
  for (SQLName_ptr item : *x->getReferencedColumns())
  {
    SQLIdentifierExpr_ptr columnName = std::dynamic_pointer_cast<SQLIdentifierExpr>(item);
    columnName->setResolvedTableSource(table);
  }

  SQLName_ptr tableName = table->getName();

  SchemaObject_ptr tableObject = repository->findTable(tableName);
  if (tableObject == nullptr)
  {
    return;
  }

  SQLStatement_ptr tableStmt = tableObject->getStatement();
  if (instanceof <SQLStatement, SQLCreateTableStatement>(tableStmt))
  {
    SQLCreateTableStatement_ptr refCreateTableStmt = std::dynamic_pointer_cast<SQLCreateTableStatement>(tableStmt);
    for (SQLName_ptr item : *x->getReferencedColumns())
    {
      SQLIdentifierExpr_ptr columnName = std::dynamic_pointer_cast<SQLIdentifierExpr>(item);
      SQLColumnDefinition_ptr column = refCreateTableStmt->findColumn(columnName->nameHashCode64());
      if (column != nullptr)
      {
        columnName->setResolvedColumn(column);
      }
    }
  }
}

// void SchemaResolveVisitorFactory::resolve(SchemaResolveVisitor_ptr visitor, SQLCreateViewStatement_ptr x)
// {
//   x->getSubQuery()
//       ->accept(visitor);
// }

// for performance
void SchemaResolveVisitorFactory::resolveExpr(SchemaResolveVisitor_ptr visitor, SQLExpr_ptr x)
{
  if (x == nullptr)
  {
    return;
  }

  string_ptr clazz = x->getClass();
  if (clazz->c_str() == SQLIdentifierExpr::class_->c_str())
  {
    visitor->visit(std::dynamic_pointer_cast<SQLIdentifierExpr>(x));
    return;
  }
  else if (clazz->c_str() == SQLIntegerExpr::class_->c_str() ||
           clazz->c_str() == SQLCharExpr::class_->c_str())
  {
    // skip
    return;
  }

  x->accept(visitor);
}

void SchemaResolveVisitorFactory::resolveUnion(SchemaResolveVisitor_ptr visitor, SQLUnionQuery_ptr x)
{
  SQLUnionOperator_ptr operator_ = x->getOperator();
  SQLSelectQuery_list_ptr relations = x->getRelations();
  if (relations->size() > 2)
  {
    for (SQLSelectQuery_ptr relation : *relations)
    {
      relation->accept(visitor);
    }
    return;
  }
  SQLSelectQuery_ptr left = x->getLeft();
  SQLSelectQuery_ptr right = x->getRight();

  BOOL_ptr bracket = (x->isParenthesized() && !(instanceof <SQLObject, SQLUnionQueryTableSource>(x->getParent())))?BOOL::TRUE:BOOL::FALSE;

  if ((!bracket) &&
      instanceof <SQLSelectQuery, SQLUnionQuery>(left) &&
                     (std::dynamic_pointer_cast<SQLUnionQuery>(left))->getOperator() == operator_ &&
                     !right->isParenthesized() &&
                     x->getOrderBy() == nullptr)
  {
    SQLUnionQuery_ptr leftUnion = std::dynamic_pointer_cast<SQLUnionQuery>(left);

    SQLSelectQuery_list_ptr rights = std::make_shared<std::list<SQLSelectQuery_ptr>>();
    rights->push_back(right);

    if (leftUnion->getRelations()->size() > 2)
    {
      for (auto getRelations_ : *leftUnion->getRelations())
      {
        rights->push_back(getRelations_);
      }
      // rights.addAll(leftUnion->getRelations());
    }
    else
    {
      for (;;)
      {
        SQLSelectQuery_ptr leftLeft = leftUnion->getLeft();
        SQLSelectQuery_ptr leftRight = leftUnion->getRight();

        if ((!leftUnion->isParenthesized()) &&
                leftUnion->getOrderBy() == nullptr &&
                (!leftLeft->isParenthesized()) &&
                (!leftRight->isParenthesized()) &&
            instanceof <SQLSelectQuery, SQLUnionQuery>(leftLeft) &&
                           (std::dynamic_pointer_cast<SQLUnionQuery>(leftLeft))->getOperator() == operator_)
        {
          rights->push_back(leftRight);
          leftUnion = std::dynamic_pointer_cast<SQLUnionQuery>(leftLeft);
          continue;
        }
        else
        {
          rights->push_back(leftRight);
          rights->push_back(leftLeft);
        }
        break;
      }
    }

    auto it_rights = rights->begin();
    for (int i = rights->size() - 1; i >= 0; i--)
    {
      std::advance(it_rights, i);
      SQLSelectQuery_ptr item = *it_rights;
      item->accept(visitor);
    }
    return;
  }

  if (left != nullptr)
  {
    left->accept(visitor);
  }

  if (right != nullptr)
  {
    right->accept(visitor);
  }
}
